package org.bookie.framework.services.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.bookie.core.model.FacebookUser;
import org.bookie.core.services.IFacebookClient;
import org.w3c.dom.Document;

import com.facebook.api.FacebookException;
import com.facebook.api.FacebookXmlRestClient;
import com.facebook.api.ProfileField;

/**
 * Implementation of the {@link IFacebookClient}
 * 
 * @author zubairov
 * 
 */
public class FacebookClientImpl implements IFacebookClient {

	private static final String FACEBOOK_API_SECRET_KEY = "org.bookie.facebook.secret";

	private static final String FACEBOOK_APPPLICATION_KEY = "org.bookie.facebook.api";
	
	private FacebookXmlRestClient client;

	private Log log;

	private String sessionKey;

	private FacebookUser user;

	/**
	 * {@inheritDoc}
	 */
	public void authenticate(String token) throws FacebookException,
			IOException {
		if (sessionKey != null) {
			log.warn("Duplicate authentication of the facebook client");
			user = null;
		}
		String apiKey = findApplicationKey();
		String secret = findSecretKey();
		client = new FacebookXmlRestClient(apiKey, secret);
		sessionKey = client.auth_getSession(token);
	}

	/**
	 * {@inheritDoc}
	 */
	public FacebookUser getAuthenticatedUser() throws FacebookException,
			IOException {
		if (user == null) {
			Collection<Integer> ids = new ArrayList<Integer>();
			ids.add(getAuthenticatedUserID());
			Set<CharSequence> fields = new HashSet<CharSequence>();
			fields.add(ProfileField.NAME.toString());
			Document userinfo = client.users_getInfo(ids, fields);
			user = new FacebookUser(userinfo);
		}
		return user;
	}

	/**
	 * {@inheritDoc}
	 */
	public boolean isAuthenticated() {
		return sessionKey != null;
	}
	
	/**
	 * {@inheritDoc}
	 */
	public int getAuthenticatedUserID() throws FacebookException, IOException {
		return client.auth_getUserId(getSessionKey());
	}

	/**
	 * Returns a session key and checks that it's not null
	 * @return
	 * @throws FacebookException 
	 */
	protected String getSessionKey() throws FacebookException {
		if (sessionKey == null) {
			throw new FacebookException(-1, "Sessionkey is null, call authenticate method first");
		}
		return sessionKey;
	}

	/**
	 * Finds application key from the environment
	 * 
	 * @return
	 * @throws FacebookException
	 */
	private String findApplicationKey() throws FacebookException {
		String application = System.getProperty(FACEBOOK_APPPLICATION_KEY);
		if (application == null) {
			String msg = "Can't find sercet key in the environment, make sure environment var "
					+ FACEBOOK_APPPLICATION_KEY + " is set";
			log.error(msg);
			throw new FacebookException(-1, msg);
		}
		return application;
	}	
	
	/**
	 * Finds secret key from the environment
	 * 
	 * @return
	 * @throws FacebookException
	 */
	private String findSecretKey() throws FacebookException {
		String secret = System.getProperty(FACEBOOK_API_SECRET_KEY);
		if (secret == null) {
			String msg = "Can't find sercet key in the environment, make sure environment var "
					+ FACEBOOK_API_SECRET_KEY + " is set";
			log.error(msg);
			throw new FacebookException(-1, msg);
		}
		return secret;
	}

	/**
	 * {@inheritDoc}
	 * @return 
	 */
	public boolean publishAction(String title, String body) throws FacebookException, IOException {
		return client.feed_publishActionOfUser(title, body);
	}
	
	
	/**
	 * @category injector
	 * @param log
	 */
	public void setLog(Log log) {
		this.log = log;
	}

}
